/**
 * @Creator: wgtpc
 * @Date: 2021/11/22 10:16
 */
package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	_ "github.com/mattn/go-sqlite3"
	"html/template"
	"math/rand"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"time"
)

const LOGDIR = "/log/"
const VIEWSDIR = "/views/"
const DBFILENAME = "default.db"

var logpath = ""
var dbpath = ""
var viewspath = ""

// 时间模板类型
const (
	templateOneYMD     = "2006-01-02"
	templateOneYMDHIS  = "2006-01-02 15:04:05"
	templateTwoYMD     = "2006/01/02"
	templateTwoMD      = "01/02"
	templateTwoYMDHIS  = "2006/01/02 15:04:05"
	templateThreeYMD   = "20060102"
	templateFourYMDHIS = "20060102150405"
)

/**
 * @Description: 返回时间格式类型
 */
var (
	DateTypeOneYMD     = dateType("yyyy-MM-dd")
	DateTypeOneYMDHIS  = dateType("yyyy-MM-dd HH:mm:ss")
	DateTypeTwoYMD     = dateType("yyyy/MM/dd")
	DateTypeTwoMD      = dateType("MM/dd")
	DateTypeTwoYMDHIS  = dateType("yyyy/MM/dd HH:mm:ss")
	DateTypeThreeYMD   = dateType("yyyyMMdd")
	DateTypeFourYMDHIS = dateType("yyyyMMddHHmmss")
)

type dateType string

/**
 * @Description: 返回格式与时间模板
 */
var typeToTemplate = map[dateType]string{
	DateTypeOneYMD:     templateOneYMD,
	DateTypeOneYMDHIS:  templateOneYMDHIS,
	DateTypeTwoYMD:     templateTwoYMD,
	DateTypeTwoMD:      templateTwoMD,
	DateTypeTwoYMDHIS:  templateTwoYMDHIS,
	DateTypeThreeYMD:   templateThreeYMD,
	DateTypeFourYMDHIS: templateFourYMDHIS,
}

type list struct {
	Key   interface{} `json:"key"`
	Value interface{} `json:"value"`
	Topda interface{} `json:"topda"`
}

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	// 解析指定文件生成模板对象
	tmpl, err := template.ParseFiles(viewspath + "main.html")
	if err != nil {
		fmt.Println("create template failed, err:", err)
		return
	}
	tmpda := getChartData()
	tmpl.Execute(w, tmpda)
}

func GetLogList(w http.ResponseWriter, r *http.Request) {
	tmploglist := make(map[string]interface{})
	//打开数据库，如果不存在，则创建
	db, err := sql.Open("sqlite3", dbpath)
	if err != nil {
		return
	}
	frda := r.URL.Query()
	if frda == nil {
		return
	}
	offset := frda["offset"][0]
	limit := frda["pageSize"][0]
	if offset == "" {
		offset = "0"
	}
	if limit == "" {
		limit = "10"
	}
	sqlstrbase := "SELECT %s FROM totla_log order by id desc"
	sqlstr := fmt.Sprintf(sqlstrbase+" limit %s,%s", "*", offset, limit)
	tmparr, _ := DoQuery(db, sqlstr)
	var cou int
	db.QueryRow(fmt.Sprintf(sqlstrbase+" limit %s,%s", "count(*) cou", "0", "1")).Scan(&cou)
	tmploglist["total"] = cou
	tmploglist["rows"] = tmparr
	loglist, _ := json.Marshal(tmploglist)
	w.Write(loglist)
}

func main() {
	getPath()
	http.HandleFunc("/", IndexHandler)
	http.HandleFunc("/loglist", GetLogList)
	http.ListenAndServe("127.0.0.1:8080", nil)

}

/**
** 获取图表数据
 */
func getChartData() list {
	var countryCapitalMap map[string]string /*创建集合 */
	countryCapitalMap = make(map[string]string)
	var i int
	for i = -7; i <= 0; i++ {
		countryCapitalMap[GetStrFixDay(i, DateTypeTwoMD)] = "0"
	}
	//打开数据库，如果不存在，则创建
	db, err := sql.Open("sqlite3", dbpath)
	if err != nil {
		return list{}
	}
	st := strconv.Itoa(int(GetIntUnix(-7)))
	et := strconv.Itoa(int(GetIntUnix(0)))
	sqls := fmt.Sprintf("SELECT count(*) as cou,time as times FROM totla_log where time between %s and %s group by time", st, et)
	rows, err := db.Query(sqls)
	if err != nil {
		return list{}
	}
	var cou string
	var times int64
	for rows.Next() {
		err = rows.Scan(&cou, &times)
		countryCapitalMap[GetStringByUnix(int(times), DateTypeTwoMD)] = cou
	}
	rows.Close()
	var keys []string
	var valuses []string
	for k, _ := range countryCapitalMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		valuses = append(valuses, countryCapitalMap[k])
	}
	var server_name string
	dayst := GetStringToUnix(GetStrFixDay(0, DateTypeOneYMD))
	dayet := dayst + 86400
	dst := strconv.Itoa(int(dayst))
	det := strconv.Itoa(int(dayet))
	sqle := fmt.Sprintf("SELECT count(*) as cou,server_name FROM totla_log where time between  %s and %s group by server_name,time ORDER BY cou desc limit 0,5", dst, det)
	rows, err = db.Query(sqle)
	if err != nil {
		return list{}
	}
	var toparr []interface{}
	Topdata := make(map[string]string)
	for rows.Next() {
		err = rows.Scan(&cou, &server_name)
		Topdata["key"] = server_name
		Topdata["val"] = cou
		toparr = append(toparr, Topdata)
	}
	rows.Close()
	var tmplist list
	tmplist.Key = keys
	tmplist.Value = valuses
	tmplist.Topda = toparr
	return tmplist
}

func DoQuery(db *sql.DB, sqlInfo string, args ...interface{}) ([]map[string]interface{}, error) {
	rows, err := db.Query(sqlInfo, args...)
	if err != nil {
		return nil, err
	}
	columns, _ := rows.Columns()
	columnLength := len(columns)
	cache := make([]interface{}, columnLength) //临时存储每行数据
	for index, _ := range cache {              //为每一列初始化一个指针
		var a interface{}
		cache[index] = &a
	}
	var list []map[string]interface{} //返回的切片
	for rows.Next() {
		_ = rows.Scan(cache...)

		item := make(map[string]interface{})
		for i, data := range cache {
			item[columns[i]] = *data.(*interface{}) //取实际类型
		}
		list = append(list, item)
	}
	_ = rows.Close()
	return list, nil
}

func getPath() string {
	dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
	dir = strings.Replace(dir, "\\", "/", -1)
	sysType := runtime.GOOS
	if sysType == "windows" {
		dir = "E:/contos/waf"
	}
	logpath = dir + LOGDIR
	if _, err := os.Stat(logpath); os.IsNotExist(err) {
		// 必须分成两步 先创建文件夹
		os.Mkdir(logpath, 0755)
		// 再修改权限
		os.Chmod(logpath, 0755)
	}
	dbpath = logpath + DBFILENAME
	viewspath = dir + VIEWSDIR
	return dir
}

/**
 * @Description: 时间戳转格式化
 * @param unix
 * @param dateType
 * @return string
 */
func GetStringByUnix(unix int, dateType dateType) string {
	return time.Unix(int64(unix), 0).Format(typeToTemplate[dateType])
}

/**
 * @Description: 格式化时间转时间戳
 * @param day
 * @return int64
 */
func GetStringToUnix(day string) int64 {
	times, _ := time.Parse(templateOneYMD, day)
	return times.Unix()
}

/**
 * @Description: 获取指定时间戳
 * @param num
 * @return int64
 */
func GetIntUnix(num int) int64 {
	todayUnix := time.Now().Unix()
	todayUnix += 24 * 60 * 60 * int64(num)
	return todayUnix
}

/**
 * @Description: 获取指定日期时间
 * @param num
 * @param dateType
 * @return string
 */
func GetStrFixDay(num int, dateType dateType) string {
	todayUnix := GetIntUnix(num)
	return GetStringByUnix(int(todayUnix), dateType)
}
func checkErr(err error) {
	if err != nil {
		panic(err)
	}
}
func RandomInt(start int, end int) int {
	rand.Seed(time.Now().UnixNano())
	random := rand.Intn(end - start)
	random = start + random
	return random
}
func RandString(len int) string {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	bytes := make([]byte, len)
	for i := 0; i < len; i++ {
		b := r.Intn(26) + 65
		bytes[i] = byte(b)
	}
	return string(bytes)
}
